//
//  UIView+Mango.m
//  Mango
//
//  Created by 胡超 on 2017/11/11.
//  Copyright © 2017年 胡超., ltd. All rights reserved.
//

#import <objc/runtime.h>

#import "UIView+Mango.h"
#import "Utils.h"

@interface MGUIViewBorderLayer : CAShapeLayer
@property (nonatomic,assign) MGBorder side;
@end
@implementation MGUIViewBorderLayer

- (void)commitUpdateFrame {
    BOOL disable = CATransaction.disableActions;
    [CATransaction setDisableActions:YES];
    [CATransaction begin];
    [self updateFrame];
    [CATransaction commit];
    // 一定要还原之前的值，否则会导致系统动画消失（如UINavigationController的push、pop动画消失）
    [CATransaction setDisableActions:disable];
}

- (void)updateFrame {
    CGSize size = self.superlayer.bounds.size;
    CGMutablePathRef path = CGPathCreateMutable();
    switch (self.side) {
        case MGBorderTop:
            CGPathMoveToPoint(path, NULL, 0, self.lineWidth/2);
            CGPathAddLineToPoint(path, NULL, size.width, self.lineWidth/2);
            break;
        case MGBorderBottom:
            CGPathMoveToPoint(path, NULL, 0, size.height-self.lineWidth/2);
            CGPathAddLineToPoint(path, NULL, size.width, size.height-self.lineWidth/2);
            break;
        case MGBorderLeft:
            CGPathMoveToPoint(path, NULL, self.lineWidth/2, 0);
            CGPathAddLineToPoint(path, NULL, self.lineWidth/2, size.height);
            break;
        case MGBorderRight:
            CGPathMoveToPoint(path, NULL, size.width-self.lineWidth/2, 0);
            CGPathAddLineToPoint(path, NULL, size.width-self.lineWidth/2, size.height);
            break;
    }
    self.path = path;
    CGPathRelease(path);
}

@end

static void(*mg_orig_UIView_layoutSubviews)(UIView *, SEL);
static void mg_UIView_layoutSubviews(UIView *self, SEL _cmd) {
    mg_orig_UIView_layoutSubviews(self, _cmd);
    if ([self borderLayer]) {
        [self.borderLayer commitUpdateFrame];
    }
    if ([self.layer.mask isKindOfClass:[CAShapeLayer class]]) {
        [self.layer.mask setFrame:self.bounds];
    }
}

@implementation UIView (Mango)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        MGHookMessageEx(self.class, @selector(layoutSubviews), (IMP)mg_UIView_layoutSubviews, (IMP*)&mg_orig_UIView_layoutSubviews);
    });
}

#pragma mark - Frame

- (CGPoint)origin   { return self.frame.origin; }
- (CGSize)size      { return self.frame.size; }
- (CGFloat)width    { return self.frame.size.width; }
- (CGFloat)height   { return self.frame.size.height; }
- (CGFloat)left     { return CGRectGetMinX(self.frame); }
- (CGFloat)right    { return CGRectGetMaxX(self.frame); }
- (CGFloat)top      { return CGRectGetMinY(self.frame); }
- (CGFloat)bottom   { return CGRectGetMaxY(self.frame); }
- (CGFloat)centerX  { return CGRectGetMidX(self.frame); }
- (CGFloat)centerY  { return CGRectGetMidY(self.frame); }

- (void)setOrigin:(CGPoint)origin {
    CGSize size = self.frame.size;
    self.frame = CGRectMake(origin.x, origin.y, size.width, size.height);
}

- (void)setSize:(CGSize)size {
    CGPoint origin = self.frame.origin;
    self.frame = CGRectMake(origin.x, origin.y, size.width, size.height);
}

- (void)setWidth:(CGFloat)width {
    CGRect frame = self.frame;
    frame.size.width = width;
    self.frame = frame;
}

- (void)setHeight:(CGFloat)height {
    CGRect frame = self.frame;
    frame.size.height = height;
    self.frame = frame;
}

- (void)setTop:(CGFloat)top {
    CGRect frame = self.frame;
    frame.origin.y = top;
    self.frame = frame;
}

- (void)setLeft:(CGFloat)left {
    CGRect frame = self.frame;
    frame.origin.x = left;
    self.frame = frame;
}

- (void)setBottom:(CGFloat)bottom {
    CGRect frame = self.frame;
    frame.origin.y = bottom - frame.size.height;
    self.frame = frame;
}

- (void)setRight:(CGFloat)right {
    CGRect frame = self.frame;
    frame.origin.x = right - frame.size.width;
    self.frame = frame;
}

- (void)setCenterX:(CGFloat)centerX {
    self.center = CGPointMake(centerX, self.center.y);
}

- (void)setCenterY:(CGFloat)centerY {
    self.center = CGPointMake(self.center.x, centerY);
}

- (CGPoint)boundsCenter {
    return CGPointMake(self.width/2, self.height/2);
}

#pragma mark - Border

- (MGUIViewBorderLayer *)borderLayer {
    return objc_getAssociatedObject(self, _cmd);
}

- (void)setBorderLayer:(MGUIViewBorderLayer *)borderLayer {
    borderLayer.zPosition = 999;
    objc_setAssociatedObject(self, @selector(borderLayer), borderLayer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
    [self.layer addSublayer:borderLayer];
}

- (void)setBorder:(CGFloat)width color:(UIColor *)color side:(MGBorder)side {
    MGUIViewBorderLayer *borderLayer = self.borderLayer;
    if (borderLayer == nil) {
        borderLayer = [MGUIViewBorderLayer layer];
        self.borderLayer = borderLayer;
    }
    [borderLayer setLineWidth:width];
    [borderLayer setLineDashPattern:NULL];
    [borderLayer setStrokeColor:color.CGColor];
    [borderLayer setSide:side];
    [borderLayer commitUpdateFrame];
}

- (void)setDottedBorder:(CGFloat)width color:(UIColor *)color dashPattern:(NSArray*)dashPattern side:(MGBorder)side {
    MGUIViewBorderLayer *borderLayer = self.borderLayer;
    if (borderLayer == nil) {
        borderLayer = [MGUIViewBorderLayer layer];
        self.borderLayer = borderLayer;
    }
    [borderLayer setLineWidth:width];
    [borderLayer setLineDashPattern:dashPattern];
    [borderLayer setStrokeColor:color.CGColor];
    [borderLayer setSide:side];
    [borderLayer commitUpdateFrame];
}

- (void)setBorderHidden:(BOOL)hidden {
    self.borderLayer.hidden = hidden;
}

- (void)setByRoundingCorners:(UIRectCorner)byRoundingCorners cornerRadius:(CGFloat)cornerRadius {
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:byRoundingCorners cornerRadii:CGSizeMake(cornerRadius, cornerRadius)];
    CAShapeLayer *cornerLayer = [CAShapeLayer layer];
    cornerLayer.frame = self.bounds;
    cornerLayer.path = path.CGPath;
    self.layer.mask = cornerLayer;
}

#pragma mark - Convenience

- (void)removeAllSubviews {
    [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
}

- (void)removeAllSubviewsExcept:(NSArray<UIView *> *)exceptViews {
    [self.subviews enumerateObjectsUsingBlock:^(__kindof UIView *subview, NSUInteger idx, BOOL * _Nonnull stop) {
        if (![exceptViews containsObject:subview]) {
            [subview removeFromSuperview];
        }
    }];
}

- (UIImage *)toImage {
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, UIScreen.mainScreen.scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 防止view缩放影响截屏区域
    CGContextConcatCTM(context, self.transform);

    [self.layer renderInContext:context];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

- (UIViewController *)viewController {
    for (UIView *nextView = self; nextView; nextView = nextView.superview) {
        UIResponder *nextResponder = nextView.nextResponder;
        if ([nextResponder isKindOfClass:[UIViewController class]]) {
            return (UIViewController *)nextResponder;
        }
    }
    return nil;
}

- (void)setSizeToFitOffset:(CGSize)offset {
    [self sizeToFit];
    [self setSize:CGSizeMake(self.width+offset.width,offset.height)];
}

#pragma mark - Animation

- (void)addRotateAnimationWithSpeed:(NSTimeInterval)speed {
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    animation.fromValue = @(0);
    animation.toValue = @(2*M_PI);
    animation.duration = speed;
    animation.repeatCount = MAXFLOAT;
    [self.layer addAnimation:animation forKey:nil];
}

@end
